package org.example.juc.lock.clh;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

@Slf4j
public class CLHLock implements Lock {

    private ThreadLocal<Node> nodeLocal = new ThreadLocal<>();

    /**
     * tail指向最后一个节点
     */
    private AtomicReference<Node> tail = new AtomicReference<>(null);

    public CLHLock() {
        tail.getAndSet(Node.EMPTY);
    }

    @Override
    public void lock() {
        // 加入尾节点
        // 如果加入成功，就普通自旋，就就听前面一个节点是否所著
        Node node = new Node(true, null);
        Node preNode = tail.get();
        while (!tail.compareAndSet(preNode, node)) {
            preNode = tail.get();
        }
        // 尾节点添加成功
        node.setPreNode(preNode);
        // 普通自旋（会一直停留在这里进行普通自旋）
        while (preNode.isLocked()) {
            // do nothing
            Thread.yield();
        }
        nodeLocal.set(node);
        log.info(Thread.currentThread().getName() + "获取锁成功");
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public void unlock() {
        // 获取当前锁节点
        Node node = nodeLocal.get();
        // 释放锁
        node.setLocked(false);
        // 用于GC
        node.setPreNode(null);
        nodeLocal.set(null);
        // 有没有重队列移除
        log.info(Thread.currentThread().getName() + "释放锁");
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
